home *** CD-ROM | disk | FTP | other *** search
/ Point Programming 1 / PPROG1.ISO / pascal / swag / win-os2.swg / 0052_Simple Termianl emulator for WINDOWS.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-02-28  |  10.0 KB  |  361 lines

  1. {
  2.   This program demonstrates a simple terminal emulator using
  3.   Serial Communications.  Windows provides support for the
  4.   communications port so your program will be able to poll the
  5.   port and send/recieve data from a remote location.
  6.  
  7.   Since this is not a program that Borland International has
  8.   developed through normal quality channels, we do not provide
  9.   technical support or establish bug lists for this demonstration
  10.   program.  It is for the sole purpose of demonstrating the use
  11.   of the available functions.
  12. }
  13.  
  14.  
  15. Program Terminal;
  16.  
  17. uses WinTypes, WinProcs, WObjects, Strings;
  18. const
  19.   idEdit     = 100;
  20.   LineWidth  = 80;  { Width of each line displayed.                  }
  21.   LineHeight = 60;  { Number of lines that are held in memory.       }
  22.  
  23.   { The configuration string below is used to configure the modem.  }
  24.   { It is set for communication port 2, 2400 baud, No parity, 8 data }
  25.   { bits, 1 stop bit.                                                }
  26.  
  27.   Config = 'com2:24,n,8,1';
  28.   CPort = 'com2';
  29.  
  30.   { An example of using communication port 1, 1200 baud, Even parity }
  31.   { 7 data bits, 2 stop bits.                                        }
  32.   {  Config = 'com1:12,e,7,2';                                       }
  33.  
  34.  
  35. type
  36.   TApp = object(TApplication)
  37.     procedure Idle; virtual;
  38.     procedure InitMainWindow; virtual;
  39.     procedure MessageLoop; virtual;
  40.   end;
  41.  
  42.   PBuffer = ^TBuffer;
  43.   TBuffer = object(TCollection)
  44.     Pos: Integer;
  45.     constructor Init(AParent: PWindow);
  46.     procedure FreeItem(Item: Pointer); virtual;
  47.     function PutChar(C: Char): Boolean;
  48.   end;
  49.  
  50.   PCommWindow = ^TCommWindow;
  51.   TCommWindow = object(TWindow)
  52.     Cid: Integer;
  53.     Buffer: PBuffer;
  54.     FontRec: TLogFont;
  55.     CharHeight: Integer;
  56.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  57.     destructor Done; virtual;
  58.     procedure Error(E: Integer; C: PChar);
  59.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  60.     procedure ReadChar; virtual;
  61.     procedure SetHeight;
  62.     procedure SetUpWindow; virtual;
  63.     procedure wmChar(var Message: TMessage);
  64.       virtual wm_Char;
  65.     procedure wmSize(var Message: TMessage);
  66.       virtual wm_Size;
  67.     procedure WriteChar;
  68.   end;
  69.  
  70. { TBuffer }
  71. { The Buffer is used to hold each line that is displayed in the main   }
  72. { window.  The constant LineHeight determines the number of lines that }
  73. { are stored.  The Buffer is preloaded with the LineHeight worth of    }
  74. { lines.                                                               }
  75. constructor TBuffer.Init(AParent: PWindow);
  76. var
  77.   P: PChar;
  78.   I: Integer;
  79. begin
  80.   TCollection.Init(LineHeight + 1, 10);
  81.   GetMem(P, LineWidth + 1);
  82.   P[0] := #0;
  83.   Pos := 0;
  84.   Insert(P);
  85.   for I := 1 to LineHeight do
  86.   begin
  87.     GetMem(P, LineWidth + 1);
  88.     P[0] := #0;
  89.     Insert(P);
  90.   end;
  91. end;
  92.  
  93. procedure TBuffer.FreeItem(Item: Pointer);
  94. begin
  95.   FreeMem(Item, LineWidth + 1);
  96. end;
  97.  
  98. { This procedure processes all incomming in formation from the comm }
  99. { port.  This procedure is called by TCommWindow.ReadChar.           }
  100.  
  101. function TBuffer.PutChar(C: Char): Boolean;
  102. var
  103.   Width: Integer;
  104.   P: PChar;
  105. begin
  106.   PutChar := False;
  107.   Case C of
  108.     #13: Pos := 0;                          { if a Carriage Return.  }
  109.     #10:                                    { if a Line Feed.        }
  110.       begin
  111.         GetMem(P, LineWidth + 1);
  112.         FillChar(P^, LineWidth + 1, ' ');
  113.         P[Pos] := #0;
  114.         Insert(P);
  115.       end;
  116.     #8:
  117.       if Pos > 0 then                       { if a Delete.           }
  118.       begin
  119.         Dec(Pos);
  120.         P := At(Count - 1);
  121.         P[Pos] := ' ';
  122.       end;
  123.    #32..#128:                               { else handle all other  }
  124.     begin                                   { displayable characters.}
  125.       P := At(Count - 1);
  126.       Width := StrLen(P);
  127.       if Width > LineWidth then             { if line is to wide     }
  128.       begin                                 { create a new line.     }
  129.         Pos := 1;
  130.         GetMem(P, LineWidth + 1);
  131.         P[0] := C;
  132.         P[1] := #0;
  133.         Insert(P);
  134.       end
  135.       else                                   { else add character    }
  136.       begin                                  { to current line.      }
  137.         P[Pos] := C;
  138.         Inc(Pos);
  139.         P[Pos] := #0;
  140.       end;
  141.     end;
  142.   end;
  143.   if Count > LineHeight then                 { if more to many lines }
  144.   begin                                      { have been added delete}
  145.     AtFree(0);                               { current line and let  }
  146.     PutChar := True;                         { the call procedure    }
  147.   end;                                       { know to scroll up.    }
  148. end;
  149.  
  150. { TCommWindow }
  151. { The CommWindow displays the incoming and out goinging text.  Note   }
  152. { that the text type by the use is displayed by                      }
  153. { being echoed back to the ReadChar procedure.  So there is no need for }
  154. { wmChar to write a character to the screen.                          }
  155. constructor TCommWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  156. begin
  157.   TWindow.Init(AParent, ATitle);
  158.   Attr.Style := Attr.Style or ws_VScroll;
  159.   Scroller := New(PScroller, Init(@Self, 1, 1, 100, 100));
  160.   Buffer := New(PBuffer, Init(@Self));
  161. end;
  162.  
  163. { Close the Comm port and deallocate the Buffer.                      }
  164. destructor TCommWindow.Done;
  165. begin
  166.   Error(CloseComm(Cid), 'Close');
  167.   Dispose(Buffer, Done);
  168.   TWindow.Done;
  169. end;
  170.  
  171. { Checks for comm errors and writes any errors.                       }
  172. procedure TCommWindow.Error(E: Integer; C: PChar);
  173. var
  174.   S: array[0..100] of Char;
  175. begin
  176.   if E >= 0 then exit;
  177.   Str(E, S);
  178.   MessageBox(GetFocus, S, C, mb_Ok);
  179. end;
  180.  
  181. { Redraw all the lines in the buffer by using ForEach.                }
  182. procedure TCommWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  183. var
  184.   I: Integer;
  185.   Font: HFont;
  186.  
  187.   procedure WriteOut(Item: PChar); far;
  188.   begin
  189.     TextOut(PaintDC, 0, CharHeight * I, Item, StrLen(Item));
  190.     inc(I);
  191.   end;
  192.  
  193. begin
  194.   I := 0;
  195.   Font := SelectObject(PaintDC, CreateFontIndirect(FontRec));
  196.   Buffer^.ForEach(@WriteOut);
  197.   DeleteObject(SelectObject(PaintDC, Font));
  198. end;
  199.  
  200. { Read a charecter from the comm port, if there is no error then call }
  201. { Buffer^.PutChar to add it to the buffer and write it to the screen. }
  202. procedure TCommWindow.ReadChar;
  203. var
  204.   Stat: TComStat;
  205.   I, Size: Integer;
  206.   C: Char;
  207. begin
  208.   GetCommError(CID, Stat);
  209.   for I := 1 to Stat.cbInQue do
  210.   begin
  211.     Size := ReadComm(CId, @C, 1);
  212.     Error(Size, 'Read Comm');
  213.     if C <> #0 then
  214.     begin
  215.       if Buffer^.PutChar(C) then
  216.       begin
  217.         ScrollWindow(HWindow, 0, -CharHeight, Nil, Nil);
  218.         UpDateWindow(HWindow);
  219.       end;
  220.       WriteChar;
  221.     end;
  222.   end;
  223. end;
  224.  
  225. procedure TCommWindow.SetUpWindow;
  226. var
  227.   DCB: TDCB;
  228. begin
  229.   TWindow.SetUpWindow;
  230.   SetHeight;
  231.  
  232. { Open for Comm2 2400 Baud, No Parity, 8 Data Bits, 1 Stop Bit }
  233.  
  234.   BuildCommDCB(Config, DCB);
  235.   Cid := OpenComm('COM2', 1024, 1024);
  236.   Error(Cid, 'Open');
  237.   DCB.ID := CID;
  238.   Error(SetCommState(DCB), 'Set Comm State');
  239.   WriteComm(Cid, 'ATZ'#13#10, 5);  { Send a reset to Modem. }
  240. end;
  241.  
  242. { Call back function used only in to get record structure for fixed   }
  243. { width font.                                                         }
  244. function GetFont(LogFont: PLogFont; TM: PTextMetric; FontType: Word;
  245.   P: PCommWindow): Integer; export;
  246. begin
  247.   if P^.CharHeight = 0 then
  248.   begin
  249.     P^.FontRec := LogFont^;
  250.     P^.CharHeight := P^.FontRec.lfHeight;
  251.   end;
  252. end;
  253.  
  254. { Get the a fixed width font to use in the TCommWindow.  Use EnumFonts  }
  255. { to save work of create the FontRec by hand.                         }
  256. { The TScroller of the main window is also updated know that the font }
  257. { height is known.                                                    }
  258.  
  259. procedure TCommWindow.SetHeight;
  260. var
  261.   DC: HDC;
  262.   ProcInst: Pointer;
  263. begin
  264.   DC := GetDC(HWindow);
  265.   CharHeight := 0;
  266.   ProcInst := MakeProcInstance(@GetFont, HInstance);
  267.   EnumFonts(DC, 'Courier', ProcInst, @Self);
  268.   FreeProcInstance(ProcInst);
  269.   ReleaseDC(HWindow, DC);
  270.  
  271.   Scroller^.SetUnits(CharHeight, CharHeight);
  272.   Scroller^.SetRange(LineWidth, LineHeight);
  273.   Scroller^.ScrollTo(0, LineHeight);
  274. end;
  275.  
  276.  
  277. { Write the character from the pressed key to the Communication Port.   }
  278. procedure TCommWindow.wmChar(var Message: TMessage);
  279. begin
  280.   if CID <> 0 then
  281.     Error(WriteComm(CId, @Message.wParam, 1), 'Writing');
  282. end;
  283.  
  284. procedure TCommWindow.wmSize(var Message: TMessage);
  285. begin
  286.   TWindow.wmSize(Message);
  287.   Scroller^.SetRange(LineWidth, LineHeight -
  288.                     (Message.lParamhi div CharHeight));
  289. end;
  290.  
  291. procedure TCommWindow.WriteChar;
  292. var
  293.   DC: HDC;
  294.   Font: HFont;
  295.   S: PChar;
  296.   APos: Integer;
  297. begin
  298.   APos := Buffer^.Count - 1;
  299.   S := Buffer^.AT(APos);
  300.   APos := (APos - Scroller^.YPos) * CharHeight;
  301.   if APos < 0 then exit;
  302.   if Hwindow <> 0 then
  303.   begin
  304.     DC := GetDC(HWindow);
  305.     Font := SelectObject(DC, CreateFontIndirect(FontRec));
  306.     TextOut(DC, 0, APos, S, StrLen(S));
  307.     DeleteObject(SelectObject(DC, Font));
  308.     ReleaseDC(HWindow, DC);
  309.   end;
  310. end;
  311.  
  312. { TApp }
  313. procedure TApp.Idle;
  314. var
  315.   Stat: TComStat;
  316.   I, Size: Integer;
  317.   C: Char;
  318. begin
  319.   if MainWindow <> Nil then
  320.     if MainWindow^.HWindow <> 0 then
  321.       PCommWindow(MainWindow)^.ReadChar;
  322. end;
  323.  
  324. procedure TApp.InitMainWindow;
  325. begin
  326.   MainWindow := New(PCommWindow, Init(Nil, 'Comm Test'));
  327. end;
  328.  
  329. { Add Idle loop to main message loop used for polling.               }
  330. procedure TApp.MessageLoop;
  331. var
  332.   Message: TMsg;
  333. begin
  334.   while True do
  335.   begin
  336.     if PeekMessage(Message, 0, 0, 0, pm_Remove) then
  337.     begin
  338.       if Message.Message = wm_Quit then
  339.       begin
  340.         Status := Message.WParam;
  341.         Exit;
  342.       end;
  343.       if not ProcessAppMsg(Message) then
  344.       begin
  345.         TranslateMessage(Message);
  346.         DispatchMessage(Message);
  347.       end;
  348.     end
  349.     else
  350.       Idle;
  351.   end;
  352. end;
  353.  
  354. var
  355.   App: TApp;
  356. begin
  357.   App.Init('Comm');
  358.   App.Run;
  359.   App.Done;
  360. end.
  361.